package cn.sherer.utils;

import java.util.Map;
import java.util.HashMap;
import java.io.IOException;
import java.net.InetAddress;
import java.util.Enumeration;
import java.io.BufferedReader;
import com.alibaba.fastjson2.JSON;
import java.net.UnknownHostException;
import com.alibaba.fastjson2.JSONObject;
import javax.xml.parsers.DocumentBuilder;
import javax.servlet.http.HttpServletRequest;
import javax.xml.parsers.DocumentBuilderFactory;

/**
 * 请求工具类
 */
public class RequestUtils {
    private String ip = "";
    private String postData = "";
    private Map<String, Object> map = new HashMap<>();
    private Map<String, String> headerMap = new HashMap<>();

    /**
     * 数据类型
     */
    public enum DataType {
        JSON, XML, UNKNOWN
    }

    public RequestUtils(HttpServletRequest request) {
        this(request, true);
    }

    public RequestUtils(HttpServletRequest request, Boolean includePostData) {
        map = new HashMap<>();
        headerMap = new HashMap<>();

        // 获取 IP 地址
        ip = getIpAddress(request);

        // 获取 Header 参数
        Enumeration<String> headers = request.getHeaderNames();
        while (headers.hasMoreElements()) {
            String key = headers.nextElement();
            String value = request.getHeader(key);
            headerMap.put(key, value);
        }

        // 获取 GET 参数
        Map<String, String[]> getMap = request.getParameterMap();
        for (String key : getMap.keySet()) {
            String[] value = getMap.get(key);
            if (value.length == 1) {
                map.put(key, value[0]);
            } else {
                map.put(key, value);
            }
        }

        // 获取 Attribute 参数
        Enumeration<String> attrs = request.getAttributeNames();
        while (attrs.hasMoreElements()) {
            String key = attrs.nextElement();
            Object value = request.getAttribute(key);
            map.put(key, value);
        }

        // 获取 POST 参数
        if (includePostData) {
            try {
                postData = getPostData(request);
                if (!postData.equals("")) {
                    try {
                        JSONObject json = JSONObject.parseObject(postData);
                        json.entrySet().forEach((entry) -> {
                            map.put(entry.getKey(), entry.getValue());
                        });
                    } catch (Exception e) {}
                }
            } catch (IOException e) {}
        }
    }

    /**
     * 获取所有参数
     * @return 所有参数
     */
    public Map<String, Object> get() {
        return map;
    }

    /**
     * 获取参数
     * @param key 参数名
     * @return 参数值
     */
    public Object get(String key) {
        return get(key, null);
    }

    /**
     * 获取参数
     * @param key 参数名
     * @param defaultValue 默认值
     * @return 参数值
     */
    public Object get(String key, Object defaultValue) {
        if (map.containsKey(key)) {
            return map.get(key);
        } else {
            return defaultValue;
        }
    }

    /**
     * 追加数据
     * @param map 数据
     * @return 追加后的数据
     */
    public Map<String, Object> putAll(Map<String, ?> map) {
        if (map != null && !map.isEmpty()) this.map.putAll(map);
        return this.map;
    }

    /**
     * 追加数据
     * @param key 参数名
     * @param value 参数值
     * @return 追加后的数据
     */
    public Map<String, Object> put(String key, Object value) {
        if (key != null && !key.trim().isEmpty()) this.map.put(key, value);
        return this.map;
    }

    /**
     * 获取所有 Header 参数
     * @return 所有 Header 参数
     */
    public Map<String, String> getHeaders() {
        return headerMap;
    }

    /**
     * 获取 Header 参数
     * @param key 参数名
     * @return 参数值
     */
    public String getHeader(String key) {
        return getHeader(key, null);
    }

    /**
     * 获取 Header 参数
     * @param key 参数名
     * @param defaultValue 默认值
     * @return 参数值
     */
    public String getHeader(String key, String defaultValue) {
        if (headerMap.containsKey(key)) {
            return StringUtils.isNull(headerMap.get(key), defaultValue);
        } else {
            return defaultValue;
        }
    }

    /**
     * 获取POST数据
     * @return POST数据
     */
    public String getPostData() {
        return postData;
    }

    /**
     * 获取 IP 地址
     * @return IP 地址
     */
    public String getIpAddress() {
        return ip;
    }

    /** 
     * 获取用户真实IP地址，不使用request.getRemoteAddr();的原因是有可能用户使用了代理软件方式避免真实IP地址, 
     * 
     * 可是，如果通过了多级反向代理的话，X-Forwarded-For的值并不止一个，而是一串IP值，究竟哪个才是真正的用户端的真实IP呢？ 
     * 答案是取X-Forwarded-For中第一个非unknown的有效IP字符串。 
     *  
     * 如：X-Forwarded-For：192.168.1.110, 192.168.1.120, 192.168.1.130, 
     * 192.168.1.100 
     *  
     * 用户真实IP为： 192.168.1.110 
     *  
     * @param request 请求
     * @return IP 地址
     */  
    public static String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_CLUSTER_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_FORWARDED");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_VIA");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("REMOTE_ADDR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
            if (ip.equals("127.0.0.1")) {
                // 根据网卡取本机配置的IP
                InetAddress inet = null;
                try {
                    inet = InetAddress.getLocalHost();
                    ip = inet.getHostAddress();
                } catch (UnknownHostException e) {
                }
            }
        }
        // 对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割
        if (ip != null && ip.length() > 15) {
            if (ip.indexOf(",") > 0) {
                ip = ip.substring(0, ip.indexOf(","));
            }
        }
        return ip;
    }

    /**
     * 获取请求参数
     * @param request 请求
     * @return 请求参数
     * @throws IOException IO异常
     */
    public static String getPostData(HttpServletRequest request) throws IOException {
        if (!request.getMethod().equalsIgnoreCase("POST")) { return ""; }
        StringBuffer sb = new StringBuffer();
        BufferedReader bufferedReader = null;
        try {
            // InputStream inputStream = request.getInputStream();
            // inputStream.available();
            // if (inputStream != null) {
            bufferedReader = request.getReader(); // new BufferedReader(new InputStreamReader(inputStream));
            char[] charBuffer = new char[128];
            int bytesRead;
            while ((bytesRead = bufferedReader.read(charBuffer)) != -1) {
                sb.append(charBuffer, 0, bytesRead);
            }
            // } else {
            // sb.append("");
            // }
        } catch (IOException ex) {
            throw ex;
        } finally {
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException ex) {
                    throw ex;
                }
            }
        }
        return  StringUtils.isNull(sb.toString(), "").trim();
    }

    /**
     * 获取数据类型
     * @param data 数据
     * @return 数据类型
     */
    public static DataType getDataType(String data) {
        data = StringUtils.isNull(data, "").trim();
        if (data.equals("")) { return DataType.UNKNOWN; }

        try {
            JSONObject.parseObject(data);
            return DataType.JSON;
        } catch (Exception e) {}

        try {
            JSON.parse(data);
            return DataType.JSON;
        } catch (Exception e) {}

        try {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            DocumentBuilder db = dbf.newDocumentBuilder();
            db.parse(data);
            return DataType.XML;
        } catch (Exception e) {}

        return DataType.UNKNOWN;
    }

}
